#pragma once

#include <iostream>
#include <vector>
#include <cstdint>
#include <cassert>
#include <cstring>
#define BUFFER_DEFAULT_SIZE 1024

class Buffer
{

private:
    std::vector<char> _buffer;

    uint64_t _reader_idx; // 读偏移
    uint64_t _writer_idx; // 写偏移

public:
    Buffer() : _reader_idx(0), _writer_idx(0), _buffer(BUFFER_DEFAULT_SIZE) {}

    char *Begin() // 返回buffer的起始位置
    {
        return &(*_buffer.begin());
    }

    char *WritePosition()
    {
        return Begin() + _writer_idx;
    }

    char *ReaderPosition()
    {
        return Begin() + _reader_idx;
    }

    // 尾部和头部的剩余空间
    uint64_t TailIdleSize()
    {
        return _buffer.size() - _writer_idx;
    }
    uint64_t HeadIdleSize()
    {
        return _reader_idx;
    }

    uint64_t ReadAbleSize()
    {
        return _writer_idx - _reader_idx;
    }

    // 将读偏移向后移动
    void MoveReadOffset(uint64_t len)
    {
        if (len == 0)
            return;
        assert(len <= ReadAbleSize());
        _reader_idx += len;
    }

    // 将写偏移向后移动
    void MoveWriteOffset(uint64_t len)
    {
        assert(len <= TailIdleSize());
        _writer_idx += len;
    }

    // 确保写空间的足够(整体足够就移动数据，不够就直接扩容)
    void EnsureWriteSpace(uint64_t len)
    {
        if (TailIdleSize() >= len)
        {
            return;
        }
        if (len <= TailIdleSize() + HeadIdleSize())
        {
            // 将数据移动到起始位置
            uint64_t rsz = ReadAbleSize();
            // 拷贝数据
            std::copy(ReaderPosition(), WritePosition(), Begin());

            _reader_idx = 0;
            _writer_idx = rsz;
        }
        else
        {
            // 总体空间不够，直接扩容，不需要移动数据
            _buffer.resize(_writer_idx + len);
        }
    }

    // 写入数据,数据地址，数据长度
    void Write(const void *data, uint64_t len)
    {
        if (len == 0)
            return;

        // 确保写入空间大小
        EnsureWriteSpace(len);

        const char *d = (const char *)data;
        std::copy(d, d + len, WritePosition());
    }

    void WriteAndPush(const void *data, uint64_t len)
    {
        Write(data, len);
        MoveWriteOffset(len);
    }

    void WriteString(const std::string &data)
    {
        Write(data.c_str(), data.size());
    }

    void WriteStringAndPush(const std::string &data)
    {
        WriteString(data);
        MoveWriteOffset(data.size());
    }

    void WriteBuffer(Buffer &data)
    {
        Write(data.ReaderPosition(), data.ReadAbleSize());
    }

    void WriteBufferAndPush(Buffer &data)
    {
        WriteBuffer(data);
        MoveWriteOffset(data.ReadAbleSize());
    }

    // 读取数据,将读取出的读取数据存入的地址，读取数据的长度
    void Read(void *buf, uint64_t len)
    {
        // 要求获取的数据大小必须小于可读数据大小，没有大于时直接读取全部
        assert(len <= ReadAbleSize());

        std::copy(ReaderPosition(), ReaderPosition() + len, (char *)buf);
    }

    void ReadAndPop(void *buf, uint64_t len)
    {
        Read(buf, len);
        MoveReadOffset(len);
    }

    std::string ReadString(uint64_t len)
    {
        assert(len <= ReadAbleSize());
        std::string str;
        str.resize(len);
        Read(&str[0], len);
        return str;
    }

    std::string ReadStringAndPop(uint64_t len)
    {
        assert(len <= ReadAbleSize());
        std::string str;
        str.resize(len);
        Read(&str[0], len);
        MoveReadOffset(len);
        return str;
    }

    char *FindCRLF()
    {
        // 查询换行符出现的位置
        char *res = (char *)memchr(ReaderPosition(), '\n', ReadAbleSize());
        return res;
    }

    // 获取一行数据
    std::string GetLine()
    {
        char *pos = FindCRLF();
        if (pos == NULL)
        {
            std::cout<<"no find...."<<std::endl;
            return "";
        }

        // 加1是把换行符也取出来
        return ReadString(pos - ReaderPosition() + 1);
    }

    std::string GetLineAndPop()
    {
        std::string str = GetLine();
        MoveReadOffset(str.size());
        return str;
    }

    // 清空缓冲区
    void Clear()
    {
        _reader_idx = 0;
        _writer_idx = 0;
    }
};